Mac OS X DP4  Release Notes Copyright © 2000 by Apple Computer, Inc.  All Rights Reserved.


Mac OS X Developer Preview 4 Release Notes:
Application Framework

The Application Framework (also referred to as the AppKit) is one of the core Cocoa frameworks. It provides functionality and associated APIs for applications, including objects for graphical user interfaces (GUIs), event-handling mechanisms, application services, and drawing and image composition facilities. In addition, it is possible to access virtually all of the classes and protocols in the Application framework using Java.

This document discusses AppKit changes in Developer Preview 4 (DP4) of Mac OS X. AppKit release notes for Mac OS X Developer Preview 3 and earlier releases can be found in another document, AppKitPreDP4.html.


Aqua

Aqua design metrics have changed since DP3.  For the most part, UI elements are now the same size as their counterparts in Platinum (the Mac OS 9 look). Text in the user interface still uses Lucida Grande, but the size in most situations is now 13pt.

Use Interface Builder's "Apply Layout Guidelines" functionality to fix up the nibs.


NSTableView

In this release several new methods have been added to NSTableView.

Two methods support "indicator images" for use in table column headers.  An arbitrary (small) image can be set to be rendered on the right side of the column header.  (This is used for example in Mail to indicate the sorting direction of the currently sorted column in a mailbox.)

- (void)setIndicatorImage:(NSImage *)anImage inTableColumn:(NSTableColumn *)tc;
- (NSImage *)indicatorImageInTableColumn:(NSTableColumn *)tc;

Support has also been added for a highlightable column header, which can be used in conjunction with row selection to highlight a particular column of the table.  (For example, as used in Mail to indicate the currently sorted column.)

- (void)setHighlightedTableColumn:(NSTableColumn *)tc;
- (NSTableColumn *)highlightedTableColumn;

Three new delegate methods have been added to help support the new indicator images and highlighted column headers.  The first method is sent  to the delegate whenever the mouse is clicked down in a column header.  The second method is sent at the time the mouse subsequently goes up and the column has been "clicked" without having been dragged anywhere.  The third method is sent at mouse-up time when the column has been dragged during the time the mouse was down.

- (void)tableView:(NSTableView *)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn;
- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn;
- (void)tableView:(NSTableView *)tableView didDragTableColumn:(NSTableColumn *)tableColumn;


NSApplication

The AppKit now handles "reopen" (rapp) AppleEvents.  These events are sent whenever Finder reactivates an already running app because someone double-clicked it again or used the dock to activate it.  By default the AppKit will handle this event by checking whether there are any visible NSWindows (not NSPanels) and, if there are none, it goes through the standard untitled document creation (the same as it does if the app is launched without any document to open).  For most document-based apps, this means an untitled document will be created.  The application delegate will also get a chance to respond to the normal untitled document delegations.

There is also a new NSApplication delegate method that apps can use if they want to have specific behavior for reopen that is different from the default behavior described above:

- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag;

If you implement this method in your application delegate, it will be called before any of the default behavior happens.  If you return YES, then NSApplication will go on to do its normal thing.  If you return NO, then NSApplication will do nothing.  So, you can either implement this, do nothing, and return NO if you do not want anything to happen at all (not recommended), or you can implement this, handle the event yourself in some custom way and return NO.  The "flag" argument indicates whether NSApplication has found any visible NSWindows in your app.  This flag can be used as an indication of whether NSApplication would do anything if you return YES.

Note that what happens to minimized windows is not determined yet, but the intent is that flag==NO indicates whether the AppKit will create a new window to satisfy the reopen event.


NSApplication now implements action methods to hide all applications (except the caller) and to unhide all applications (including the caller).

- (void)hideOtherApplications:(id)sender;
- (void)unhideAllApplications:(id)sender;

In DP4 unhideAllApplications will cause each application to order its windows to the front, which could obscure the currently active window in the active application.


Document modal API

The document modal API introduced in DP3 implies a nesting model that fails in the case of multiple windows presenting sheets.  With that API, the caller expects to return from the call only after the modal session has been dismissed.  However, this cannot be supported if the user wants to run multiple modal sessions and expects to dismiss the sessions in an arbitrary order.

DP4 introduces new API that returns immediately after beginning a modal session, then invokes a callback when the modal session is dismissed. The current document modal API will be deprecated, but will still work through DP4.

To start a document modal session, NSApplication.h:

- (void)beginSheet:(NSWindow *)sheet modalForWindow:(NSWindow *)docWindow modalDelegate:(id)modalDelegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;

The didEndSelector method is optional.  If it is implemented by the modalDelegate, this method is invoked after the modal session has ended and passed the code and the caller specified contextInfo.  The didEndSelector should have the following signature:

- (void)didEndSheet:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;

To end a document modal session, the sheet window must be specified:

- (void)endSheet:(NSWindow *)sheet;
- (void)endSheet:(NSWindow *)sheet returnCode:(int)code;

In NSPanel.h:

void NSBeginAlertSheet(NSString *title, NSString *defaultButton, NSString *alternateButton, NSString *otherButton, NSWindow *docWindow, id modalDelegate, SEL willEndSelector, SEL didEndSelector, void *contextInfo, NSString *msg, ...);

void NSBeginInformationalAlertSheet(NSString *title, NSString *defaultButton, NSString *alternateButton, NSString *otherButton, NSWindow *docWindow, id modalDelegate, SEL willEndSelector, SEL didEndSelector, void *contextInfo, NSString *msg, ...);

void NSBeginCriticalAlertSheet(NSString *title, NSString *defaultButton, NSString *alternateButton, NSString *otherButton, NSWindow *docWindow, id modalDelegate, SEL willEndSelector, SEL didEndSelector, void *contextInfo, NSString *msg, ...);

Note that the arguments are ordered differently than the NSRunAlertPanel() calls, in order to assure they are grouped better and provide better type checking of arguments.

Implementing the willEndSelector and didEndSelector method is optional.  If willEndSelector is implemented by the modalDelegate, this method is invoked after the modal session has ended but before dismissing the sheet.  The didEndSelector is invoked after dismissing the sheet.  The willEndSelector and didEndSelector methods should have the following signatures:

- (void)willEndSheet:(NSWindow *)sheet returnCode:(int)code contextInfo:(void *)contextInfo;
- (void)didEndSheet:(NSWindow *)sheet returnCode:(int)code contextInfo:(void *)contextInfo;

In NSSavePanel.h:

- (void)beginSheetForDirectory:(NSString *)path file:(NSString *)name modalForWindow:(NSWindow *)docWindow modalDelegate:(id)delegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;

Implementing the didEndSelector is optional.  If didEndSelector is implemented by the modalDelegate, this method is invoked after the modal session has ended but before dismissing the save panel sheet.  The didEndSelector method may dismiss the save panel itself; it will be dismissed on return from the method otherwise.

- (void)didEndSavePanel:(NSSavePanel *)savePanel returnCode:(int)code contextInfo:(void *)contextInfo;

For the next release we intend on putting doc modal sheet support into NSDocument.


NSEvent

A class method has been added to NSEvent.h to export the current mouse position, in screen coordinates:

+ (NSPoint)mouseLocation;

An event type, NSScrollWheel, has been added to NSEvent.h to support scroll-wheel events. In addition, the following method has been added to NSResponder.h:

- (void)scrollWheel:(NSEvent *)theEvent;

If an NSScrollView is the firstResponder, an NSScrollWheel event will be treated the same as a click on the scroller arrow.

NSEvent.h also defines methods to obtain the delta along each axis for a scroll wheel event:

- (float)deltaX;
- (float)deltaY;
- (float)deltaZ;


Support for dynamic screen changes

DP4 includes support for dynamic screen changes.  If the user changes the screen resolution or size, the application delegate will be notified and windows will be repositioned if necessary to keep them on the visible screen and maintain their relative screen locations.

An application notification and delegate method have been added:

NSString *NSApplicationDidChangeScreenParametersNotification;

- (void)applicationDidChangeScreenParameters:(NSNotification *)notification;


NSDrawer

NSDrawers can now have delegates, with the following delegate and delegate notification methods:

@interface NSObject(NSDrawerNotifications)
- (void)drawerWillOpen:(NSNotification *)notification;
- (void)drawerDidOpen:(NSNotification *)notification;
- (void)drawerWillClose:(NSNotification *)notification;
- (void)drawerDidClose:(NSNotification *)notification;
@end

@interface NSObject(NSDrawerDelegate)
- (BOOL)drawerShouldOpen:(NSDrawer *)sender;
- (BOOL)drawerShouldClose:(NSDrawer *)sender;
- (NSSize)drawerWillResizeContents:(NSDrawer *)sender toSize:(NSSize)contentSize;
@end

The calls to the method drawerWillResizeContents:toSize: are not yet implemented.  Additional methods on NSDrawer itself are:

- (void)setDelegate:(id)anObject;
- (id)delegate;

- (void)open:(id)sender;
- (void)close:(id)sender;


NSTabView

NSTabView has improved its support for truncation of its text label.  When there is not enough space to display all of the NSTabViewItem's labels, truncation will be performed beginning first with longer labels.  Note that, there have been subtle changes to the methods that subclasses of NSTabViewItem override to display their own label.  Though the method signature remains the same, the usage has changed.

- (void)drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)labelRect;

This method draws the tab label in labelRect, which is the area in between the curved end caps. shouldTruncateLabel is a hint that the label should be truncated; if shouldTruncateLabel is YES, then labelRect < ceil([... sizeOfLabel:YES])

- (NSSize)sizeOfLabel:(BOOL)flag;    

This method returns the minimum or nominal size of the tab label.    The flag indicates whether you should return the minimum or nominal label size.  The returned value is used to compute the range of legal sizes for the tab label.



Loading NEXTSTEP 3.x .nib Files

The unarchiving mappings from old NEXTSTEP classes (like NXBrowser) to OPENSTEP classes (like NSBrowser) is now disabled by default.  The temporary user default NSEnableNEXTSTEPArchiverMappings with a value of YES can be used to re-enable the installation of these mappings.

Note that the NXStringTable, NXBundle, StreamTable, and Storage classes have been removed from the ObjC runtime, so if the nib contains instances of these classes, it also will not load, and there is no way to correct that.  For now, the List and HashTable classes, and the NXHashTable functions, remain, but you should anticipate these things being removed from the runtime in the future.


objc_getClasses

The objc_getClasses() function in objc/objc-runtime.h is obsolete. You should use the new objc_getClassList() function instead, as described in the comment in the header.


NSPDFImageRep

Support has been added to NSPDFImageRep to choose which page of a multipage document to render. Previously, only the first page was drawn.

- (void)setCurrentPage:(int)page;
- (int)currentPage;
- (int)pageCount;

The first two methods set and get the current page to display. The page index is zero based. pageCount returns the number of pages in the document. After calling setCurrentPage:, the rectangle returned by -[NSPDFImageRep bounds] is for the new page.


NSColor

A new method has been added to the list of system colors:

+ (NSColor*)windowBackgroundColor;

Under Aqua, this now returns an NSPatternColor that will draw the ruled lines for the window background.

controlColor has also been modified to return the same pattern since the most common usage for it is to draw the background of a non-rectangular but opaque control. If you use control color assuming that it is a solid, you may an incorrect appearance. You should use lightGrayColor in it's place.

A number of system colors, while still valid, are no longer meaningful under Aqua. These include any of the ones with 'control' in their name. They return the old Platinum appearance colors which are usually a shade of gray.

Dynamic system colors are no longer updated from defaults, except for those few (currently only two, the text selection color and control selection color) that are settable in the Preferences app.

NSWorkspace

A new method has been added that allows you to notify the Finder when a new file has been added.

- (void)noteFileSystemChanged:(NSString*)path;

NSDocument and NSSavePanel as been modified to use this method when saving a file. If you create a file directly, you should call this method so that the Finder can update the folder if it is open.


NSSavePanel

A new delegate method has been added to NSSavePanel that notifies the delegate when the save panel is about to expand or collapse. You may get a call to this the first time the panel is shown as it collapses or expands based on the last state it was in.

- (void)panel:(id)sender willExpand:(BOOL)expanding;

A new function that goes along with the new delegate method returns the current state of the save panel. Note that for the open panel, this currently always returns YES:

(BOOL)isExpanded;


NSOpenGLContext, NSOpenGLView

Support has been added for rendering OpenGL into a view in the AppKit. You can get direct access to the OpenGL system via NSOpenGLContext  and its assocated NSOpenGLPixelFormat class or you can just create an instance of NSOpenGLView and when you lockFocus on the view, the current OpenGL context will be set  to the view's. You cannot draw using regular 2D drawing in the view since it is completely covered by the 3D context.

NSOpenGLView has 2 public methods. One is an init method where you can pass in a custom pixel format to choose a specific set of features for rendering. If you just drag in an NSOpenGLView in InterfaceBuilder, it is equivalent to passing in nil for format in which case, the system will choose the best format it can based on the hardware capabilities.

- (id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat*)format;
- (NSOpenGLContext*)openGLContext;

If you wish to draw to the view outside of a lockFocus call, you can simply set the current context directly via [[glView openGLContext] makeCurrentContext];.

For full screen or offscreen drawing, you will need to create your own NSOpenGLContext. Though NSOpenGLContext does allow you to associate any view with the context, you will have to handle any view frame changes yourself. It is recommended you use NSOpenGLView in these cases.


Defaults

The kit no longer registers several obsolete defaults, including NSHost and several for NSPrinter.


genstrings

genstrings now always writes out Unicode files. These can be edited in TextEdit or other text editors capable of dealing with Unicode.

For localizable strings with no table specified, genstrings would just write the output to stdout. It will now instead write the output to Localizable.strings, which is the default table consulted by the NSBundle/CFBundle code when no table is specified.


Standard About Panel

ProjectVersion and SystemVersionName keys are no longer looked for in the about panel options dictionary.  These keys were not documented publically. The correct key to use is ApplicationVersion, which should have a value to indicate the product version name, for instance "Mac OS X" (for system apps), "Web Objects 4.5," "FooSimulator 2000," etc. If not specified in the options dictionary, the CFBundleShortVersionString key in from the bundle info plist will be picked up; if that is not there, the old form, NSAppVersion will be used. (Note that in DP4 there is a bug that prevents automatic picking up of the CFBundleShortVersionString string from Info.plist.)

For internal apps using the internal about panel function, this field is automatically populated with the product version name, "Mac OS X".

The Version key, if not specified, is now picked up from CFBundleVersion key in the bundle info plist. If that is not there, the old form, NSBuildVersion will also be looked for.

The InfoPlist.html release note has been updated with the other changes in Info.plist keys.


Text

Macintosh documents created with SimpleText (MacOS types TEXT, sEXT, ttro) can now be loaded into attributed strings when using initWithPath:documentAttributes: and initWithURL:documentAttributes:.   Embedded graphics are supported (such files are not directly creatable with SimpleText itself, but stored as PICT resources).  Note that there are no plans for supporting saving of documents in SimpleText format.

In all methods taking a documentAttributes: parameter, if not NULL, on return it may now also contain the following additional keys:

@"DocumentType": NSString indicating how the document was interpreted; see NSAttributedString.h for possible values
@"CharacterEncoding": For plain text files only; NSNumber containing unsigned int specifying NSStringEncoding used to interpret the file

The following method has been added to NSMutableAttributedString as an general funnel point for all document loading:

- (BOOL)readFromURL:(NSURL *)url options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict;

This method is like initWithURL:documentAttributes:; except it can be reused to reload the file into an existing attributed string, and the behavior can be customized with the options dictionary. If not NULL, this dictionary may contain the following values:

@"CharacterEncoding": For plain text documents; NSNumber containing unsigned int NSStringEncoding to be used if the encoding cannot be determined
@"BaseURL": For HTML documents; NSURL containing base URL
@"DefaultAttributes": NSDictionary containing attributes to be applied to plain files


NSLayoutManager

NSLayoutManager now include support for temporary attributes.  These attributes are used only for on-screen drawing and are not persistent in any way.  NSTextView uses them to color misspelled words when continuous spellchecking is enabled.  Currently the only temporary attributes that will be recognized are those related to colors and underlines.  The following temporary-attribute related methods are available for NSLayoutManager:

- (NSDictionary *)temporaryAttributesAtCharacterIndex:(unsigned)charIndex effectiveRange:(NSRangePointer)effectiveCharRange;
- (void)setTemporaryAttributes:(NSDictionary *)attrs forCharacterRange:(NSRange)charRange;
- (void)addTemporaryAttributes:(NSDictionary *)attrs forCharacterRange:(NSRange)charRange;
- (void)removeTemporaryAttribute:(NSString *)name forCharacterRange:(NSRange)charRange;


Linking Carbon.framework

AppKit.framework no longer links against Carbon.framework, but against subframeworks in there. It still brings in most of the frameworks covered by the umbrella framework; ones that are excluded include Nav and CommonPanels. If your app pulls in Carbon symbols explicitly from these (and other not included frameworks) you should probably request to pull in Carbon.framework explicitly.


NSImage

[NSImage imageNamed:@"foo"] will now find foo.tiff in the localized resources directory (for the main language) before it finds some other type of foo in the non-localized directory. This behavior is changed in  that before a non-localized "foo" (with a recognized image file extension) would be found before a localized "foo". This change was done for tiff only, for performance reasons.


NSPanel

NSPanel now has a special application activation behavior. NSPanel instances that satisfy the following conditions do not automatically activate their applications. This behavior makes developing accessory floating panel gadgets like input method palette panels easy.

Non-activating conditions:
1) It is an utility window
2) It is a floating panel
3) becomesKeyOnlyIfNeeded == YES
4) The mouse-down event occurs in a view that does not accept the first responder status


NSCell

The deprecated enum values NSStateMixed, NSStateOff, and NSStateOn have been removed from NSCell.h. Use NSMixedState, NSOffState, and NSOnState instead.


NSMenu

+(void)popUpContextMenu:(NSMenu*)menu withEvent:(NSEvent*)event forView:(NSView*)view;

This method will display an NSMenu as a context menu inside the view. Use this if the context menu support in NSView does not suit your needs. The menu will pop up positioned next to the cursor.


NSMatrix, NSTextField

The following methods have been made obsolete and removed from public headers. They are deprecated and an NSFormatter should be used instead to handle bad input.

- (SEL)errorAction;
- (void)setErrorAction:(SEL)aSelector;


NSMovieView

NSMovieView still not functional in Developer Release 4.


NSMenu

Images in popups and menus are still not working; this is a bug.


NSScreen

The following methods are private and should not be listed in NSScreen.h at all. They will be removed from the headers post-DP4:

- (NSRect)_savedVisibleFrame;
- (void)_saveVisibleFrame


Multiple Monitors

There are a number of known problems associated with rearranging the configuration of multiple monitors.  Moving the menu bar to a secondary monitor is especially problematic.  For DP4, we recommend that you leave the menu bar on the main monitor.


NSWindow

DP3 reentrancy problems with the NSWindow methods -[NSWindow setMiniwindowTitle:] and -[NSWindow setTitle:] have been fixed in DP4. These were due to dock interaction, which could cause runloop to be reentered.